experimental(agent): Add experimental coding-agent adapters with NeMo-Relay telemetry#1995
Conversation
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR introduces five experimental agent adapters for the NeMo Agent Toolkit, integrating with NeMo Relay for telemetry collection. It adds Claude Code, Codex, Cursor, Hermes, and OpenClaw workflow adapters, a relay telemetry conversion module, example configurations, comprehensive documentation, and repository wiring updates. ChangesExperimental Agent Adapters with Relay Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
…ration Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
…de-agent-adapter Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (4)
packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py (1)
124-145: ⚡ Quick winConsider a negative-path test for malformed JSONL.
Once
load_atof_jsonlis hardened to skip bad lines, add a case writing a partial/invalid line to confirm valid events are still loaded. This guards the Relay timeout injection path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py` around lines 124 - 145, Add a negative-path test that writes a JSONL file containing both a valid event and a malformed/partial line, then call load_atof_jsonl and inject_atof_jsonl to verify the loader skips the bad line and only returns/injects the valid event: create a file with one well-formed event JSON and one broken line, assert load_atof_jsonl(path) returns only the valid event, subscribe to Context.intermediate_step_manager, call inject_atof_jsonl(path, context=...), and assert the captured IntermediateStep(s) correspond only to the valid event (check event types, parent_id, and count).packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py (1)
66-83: 💤 Low valueDocstring style: prefer Google-style.
The docstring uses NumPy-style
Parameters\n----------sections. As per coding guidelines, "Provide Google-style docstrings for every public module, class, function and CLI command" (i.e. anArgs:section).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py` around lines 66 - 83, The docstring for relay_events_to_intermediate_steps uses NumPy-style Parameters/---------- formatting; update it to a Google-style docstring: replace the Parameters section with an Args: block listing events, root_parent_id, and function_ancestry (each with a one-line description and types where helpful), and keep the brief top description and Returns/Examples if present in Google style; ensure the function name relay_events_to_intermediate_steps and parameter names root_parent_id and function_ancestry are referenced exactly as in the signature.examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py (1)
376-379: 💤 Low valueUnreachable non-relay CLI branch.
_run_claude_codeonly routes to_run_claude_code_cliwhenrelay_enabledis true; otherwise it uses the SDK path. As a result theelsebranch in_run_claude_code_cli(lines 327-328,_build_claude_command) and the non-relay portions of theFileNotFoundErrormessaging are dead code. Either wire up a CLI fallback for the non-relay case or drop the unused branch to avoid confusion.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py` around lines 376 - 379, The current routing makes the CLI path unreachable unless config.relay_enabled is true, leaving the else branch in _run_claude_code_cli and parts of the FileNotFoundError message unused; either remove the dead CLI fallback code (drop the else branch in _run_claude_code_cli and related non-relay FileNotFoundError text) or add a clear CLI fallback path by updating _run_claude_code to call _run_claude_code_cli when relay is disabled (or when a new config flag indicates CLI mode), and ensure _build_claude_command is invoked only in the supported branch; modify the logic in _run_claude_code, _run_claude_code_cli, and any FileNotFoundError messaging accordingly so there is no dead-code path left.examples/experimental/openclaw_agent_adapter/README.md (1)
58-58: 💤 Low valueAvoid possessive
'swith inanimate objects (doc style)."OpenClaw's plugin system" (and "the example's ..." on Line 308) use possessive
'swith inanimate nouns. Reword, e.g. "the plugin system of OpenClaw" / "the example settings".As per coding guidelines: "Documentation in Markdown files should not contain usage of a possessive 's with inanimate objects."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/openclaw_agent_adapter/README.md` at line 58, Replace possessive "'s" usages with "of" phrasing for inanimate nouns: change "OpenClaw's plugin system" to "the plugin system of OpenClaw" and "the example's ..." to "the example settings" (or "settings of the example") in the README content; search for and update any other occurrences of possessive "'s" applied to inanimate objects so documentation follows the style guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/experimental/claude_code_agent_adapter/pyproject.toml`:
- Around line 27-45: Add the example to the root project examples list and
rename the uv source to a nat_-prefixed name: in root pyproject.toml include
"nat_claude_code_agent_adapter" in the examples/installable examples array so
the example is packaged, and in
examples/experimental/claude_code_agent_adapter/pyproject.toml change the
[tool.uv.sources] key from "nvidia-nat" to a nat_-prefixed identifier (e.g.,
"nat_nvidia_nat" or "nat_nvidia-nat") so the source reads like nat_nvidia_nat =
{ path = "../../..", editable = true }; leave the project.name and the entry
point nat_claude_code_agent_adapter = "nat_claude_code_agent_adapter.register"
intact.
In `@examples/experimental/codex_agent_adapter/package.json`:
- Around line 4-6: Update the dependency declaration for `@openai/codex-sdk` in
package.json to pin it to the tested version/range instead of "latest" — replace
the current "`@openai/codex-sdk`": "latest" entry with a stable version (e.g.,
"`@openai/codex-sdk`": "0.135.0" or a constrained range "`@openai/codex-sdk`":
"^0.135.0") so installs align with the package-lock.json and the README's
supported Codex version.
In `@examples/experimental/codex_agent_adapter/pyproject.toml`:
- Around line 30-47: The root pyproject.toml needs the new example registered:
add "nat_codex_agent_adapter" to the top-level examples = [...] array and add a
corresponding [tool.uv.sources] entry named nat_codex_agent_adapter that points
to the example path (nat_codex_agent_adapter = { path =
"examples/experimental/codex_agent_adapter", editable = true }) so the package
declared as name = "nat_codex_agent_adapter" and the entry point nat.components
-> nat_codex_agent_adapter = "nat_codex_agent_adapter.register" in the example
pyproject.toml is discoverable by the root build/configuration.
In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`:
- Around line 397-400: The `_run_codex_cli` implementation contains a dead
non-relay branch (the `else: command = _build_codex_command(...)` path) that is
never used because `_run_codex` only calls `_run_codex_cli` when
`config.relay_enabled` is true and all non-relay calls go to `_run_node_sdk`;
remove the unreachable branch (and the helper `_build_codex_command` if it
becomes unused) or, if you intended to support non-relay CLI execution, change
`_run_codex` to route non-relay calls into `_run_codex_cli`. Also update the
`FileNotFoundError` handler wording inside `_run_codex_cli` to refer
specifically to the Codex relay binary (and remove “Codex CLI” wording) so the
error message matches the actual execution path. Ensure any removed helper
references (e.g., `_build_codex_command`) are cleaned up and tests/usage updated
accordingly.
In `@examples/experimental/cursor_agent_adapter/pyproject.toml`:
- Around line 27-44: Add the missing example registration: update the root
pyproject.toml to include "nat_cursor_agent_adapter" in the top-level examples =
[...] list, and add a corresponding entry under [tool.uv.sources] named
nat_cursor_agent_adapter that maps the package name to the example package
(using editable = true) so the nat_cursor_agent_adapter component and its
entry-point (nat_cursor_agent_adapter = "nat_cursor_agent_adapter.register") are
discoverable and installable.
In `@examples/experimental/cursor_agent_adapter/README.md`:
- Line 150: The phrase "Relay's raw event file" in README.md uses a possessive
's on an inanimate object; update the sentence to use a non-possessive form such
as "the raw Relay event file" (or "Relay raw event file") so the documentation
follows the guideline against using possessive 's with inanimate objects; search
for the exact string "Relay's raw event file" and replace it accordingly in the
README.md content.
In `@examples/experimental/hermes_agent_adapter/configs/config-relay.yml`:
- Around line 4-11: The config currently enables relay (workflow._type:
hermes_agent, relay_enabled: true) but does not set relay_atof_output_dir, so
ATOF events are written to a temp dir and removed; update the config to set
relay_atof_output_dir to the README's inspect path (e.g.
.tmp/nat-relay-hermes-atof) so the events.jsonl file is preserved for the `cat
./.tmp/nat-relay-hermes-atof/events.jsonl` step, or alternatively change the
README to point to the phoenix config that already sets relay_atof_output_dir.
In `@examples/experimental/hermes_agent_adapter/pyproject.toml`:
- Around line 27-44: The root pyproject.toml must include the example module and
a uv source for nat_hermes_agent_adapter; add "nat_hermes_agent_adapter" to the
root examples array and add a [tool.uv.sources] entry mapping
nat_hermes_agent_adapter to the examples/experimental/hermes_agent_adapter path
(editable true) so the project name nat_hermes_agent_adapter and its existing
[tool.uv.sources] usage in the example match the root config.
In `@examples/experimental/hermes_agent_adapter/README.md`:
- Line 126: The sentence "You can inspect Relay's raw event file:" uses a
possessive 's with an inanimate object; update the README line that currently
reads "You can inspect Relay's raw event file:" (search for that exact string)
to a non-possessive phrasing such as "You can inspect the raw event file of
Relay:" or "You can inspect the Relay raw event file:" to comply with the
documentation guideline.
In
`@examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.py`:
- Around line 273-274: The public workflow function openclaw_agent (decorated
with `@register_function` and accepting config: OpenClawAgentWorkflowConfig and
_builder: Builder) must include a return type hint and a Google-style docstring;
update the signature to add the appropriate return type (e.g., ->
YourReturnType) and add a docstring immediately below the def that documents
Args (config, _builder) and Returns (describe return value and type), mentioning
any side effects or exceptions as needed so the function complies with public
API guidelines.
In `@packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py`:
- Around line 52-63: The loader load_atof_jsonl currently calls json.loads on
every non-empty line and will raise on a malformed line; change it to open the
file with encoding="utf-8" and wrap the json.loads call in a try/except (catch
json.JSONDecodeError/ValueError) so malformed lines are skipped (optionally log
or count them) and valid dict events continue to be appended to the events list;
keep the function signature and return type the same and only alter the file
open call and the per-line parsing logic in load_atof_jsonl.
---
Nitpick comments:
In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`:
- Around line 376-379: The current routing makes the CLI path unreachable unless
config.relay_enabled is true, leaving the else branch in _run_claude_code_cli
and parts of the FileNotFoundError message unused; either remove the dead CLI
fallback code (drop the else branch in _run_claude_code_cli and related
non-relay FileNotFoundError text) or add a clear CLI fallback path by updating
_run_claude_code to call _run_claude_code_cli when relay is disabled (or when a
new config flag indicates CLI mode), and ensure _build_claude_command is invoked
only in the supported branch; modify the logic in _run_claude_code,
_run_claude_code_cli, and any FileNotFoundError messaging accordingly so there
is no dead-code path left.
In `@examples/experimental/openclaw_agent_adapter/README.md`:
- Line 58: Replace possessive "'s" usages with "of" phrasing for inanimate
nouns: change "OpenClaw's plugin system" to "the plugin system of OpenClaw" and
"the example's ..." to "the example settings" (or "settings of the example") in
the README content; search for and update any other occurrences of possessive
"'s" applied to inanimate objects so documentation follows the style guideline.
In `@packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py`:
- Around line 66-83: The docstring for relay_events_to_intermediate_steps uses
NumPy-style Parameters/---------- formatting; update it to a Google-style
docstring: replace the Parameters section with an Args: block listing events,
root_parent_id, and function_ancestry (each with a one-line description and
types where helpful), and keep the brief top description and Returns/Examples if
present in Google style; ensure the function name
relay_events_to_intermediate_steps and parameter names root_parent_id and
function_ancestry are referenced exactly as in the signature.
In
`@packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py`:
- Around line 124-145: Add a negative-path test that writes a JSONL file
containing both a valid event and a malformed/partial line, then call
load_atof_jsonl and inject_atof_jsonl to verify the loader skips the bad line
and only returns/injects the valid event: create a file with one well-formed
event JSON and one broken line, assert load_atof_jsonl(path) returns only the
valid event, subscribe to Context.intermediate_step_manager, call
inject_atof_jsonl(path, context=...), and assert the captured
IntermediateStep(s) correspond only to the valid event (check event types,
parent_id, and count).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 7ef97f18-5301-4c0a-a9da-a9545b40d66b
⛔ Files ignored due to path filters (10)
docs/source/_static/claude_code_agent_adapter/phoenix-relay-trace.pngis excluded by!**/*.pngdocs/source/_static/codex_agent_adapter/phoenix-relay-trace.pngis excluded by!**/*.pngdocs/source/_static/cursor_agent_adapter/phoenix-relay-trace.pngis excluded by!**/*.pngdocs/source/_static/hermes_agent_adapter/phoenix-relay-trace.pngis excluded by!**/*.pngexamples/experimental/claude_code_agent_adapter/uv.lockis excluded by!**/*.lockexamples/experimental/codex_agent_adapter/package-lock.jsonis excluded by!**/package-lock.jsonexamples/experimental/codex_agent_adapter/uv.lockis excluded by!**/*.lockexamples/experimental/cursor_agent_adapter/uv.lockis excluded by!**/*.lockexamples/experimental/hermes_agent_adapter/uv.lockis excluded by!**/*.lockexamples/experimental/openclaw_agent_adapter/uv.lockis excluded by!**/*.lock
📒 Files selected for processing (46)
.gitignoreexamples/README.mdexamples/experimental/claude_code_agent_adapter/README.mdexamples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/claude_code_agent_adapter/configs/config-relay.ymlexamples/experimental/claude_code_agent_adapter/data/eval-smoke.jsonexamples/experimental/claude_code_agent_adapter/pyproject.tomlexamples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/__init__.pyexamples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.pyexamples/experimental/codex_agent_adapter/README.mdexamples/experimental/codex_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/codex_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/codex_agent_adapter/configs/config-relay.ymlexamples/experimental/codex_agent_adapter/data/eval-smoke.jsonexamples/experimental/codex_agent_adapter/package.jsonexamples/experimental/codex_agent_adapter/pyproject.tomlexamples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/__init__.pyexamples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/codex_sdk_runner.mjsexamples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.pyexamples/experimental/cursor_agent_adapter/README.mdexamples/experimental/cursor_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/cursor_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/cursor_agent_adapter/configs/config-relay.ymlexamples/experimental/cursor_agent_adapter/data/eval-smoke.jsonexamples/experimental/cursor_agent_adapter/pyproject.tomlexamples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/__init__.pyexamples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.pyexamples/experimental/hermes_agent_adapter/README.mdexamples/experimental/hermes_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/hermes_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/hermes_agent_adapter/configs/config-relay.ymlexamples/experimental/hermes_agent_adapter/data/eval-smoke.jsonexamples/experimental/hermes_agent_adapter/pyproject.tomlexamples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/__init__.pyexamples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.pyexamples/experimental/openclaw_agent_adapter/README.mdexamples/experimental/openclaw_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/openclaw_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/openclaw_agent_adapter/configs/config-relay.ymlexamples/experimental/openclaw_agent_adapter/data/eval-smoke.jsonexamples/experimental/openclaw_agent_adapter/pyproject.tomlexamples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/__init__.pyexamples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.pypackages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.pypackages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pyproject.toml (1)
129-180:⚠️ Potential issue | 🟠 Major | ⚡ Quick winMissing OpenClaw root wiring in
examplesandtool.uv.sources.The new adapter set is incomplete here:
nat_openclaw_agent_adapteris missing from both the top-levelexampleslist and[tool.uv.sources], even though the experimental examples index includes OpenClaw. This can leave one adapter undiscoverable via the same root example install flow as the others.Suggested patch
[tool.setuptools_dynamic_dependencies.optional-dependencies] examples = [ "nat_adk_demo", @@ "nat_multi_frameworks", "nat_notebooks", + "nat_openclaw_agent_adapter", "nat_parallel_executor", @@ [tool.uv.sources] # Examples nat_adk_demo = { path = "examples/frameworks/adk_demo", editable = true } @@ nat_multi_frameworks = { path = "examples/frameworks/multi_frameworks", editable = true } nat_notebooks = { path = "examples/notebooks", editable = true } +nat_openclaw_agent_adapter = { path = "examples/experimental/openclaw_agent_adapter", editable = true } nat_parallel_executor = { path = "examples/control_flow/parallel_executor", editable = true }Also applies to: 233-322
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pyproject.toml` around lines 129 - 180, The examples and UV source roots are missing the new OpenClaw adapter; add "nat_openclaw_agent_adapter" to the top-level examples array (the examples list shown) and also add the corresponding "nat_openclaw_agent_adapter" entry under the [tool.uv.sources] section so the adapter is discoverable via the same root/example install flow as the other adapters.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@pyproject.toml`:
- Around line 129-180: The examples and UV source roots are missing the new
OpenClaw adapter; add "nat_openclaw_agent_adapter" to the top-level examples
array (the examples list shown) and also add the corresponding
"nat_openclaw_agent_adapter" entry under the [tool.uv.sources] section so the
adapter is discoverable via the same root/example install flow as the other
adapters.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: bc3e34aa-91fa-4f1d-86e8-e048ac3da75e
⛔ Files ignored due to path filters (6)
examples/experimental/claude_code_agent_adapter/uv.lockis excluded by!**/*.lockexamples/experimental/codex_agent_adapter/package-lock.jsonis excluded by!**/package-lock.jsonexamples/experimental/codex_agent_adapter/uv.lockis excluded by!**/*.lockexamples/experimental/cursor_agent_adapter/uv.lockis excluded by!**/*.lockexamples/experimental/hermes_agent_adapter/uv.lockis excluded by!**/*.lockuv.lockis excluded by!**/*.lock
📒 Files selected for processing (9)
examples/experimental/codex_agent_adapter/package.jsonexamples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.pyexamples/experimental/cursor_agent_adapter/README.mdexamples/experimental/hermes_agent_adapter/README.mdexamples/experimental/hermes_agent_adapter/configs/config-relay.ymlexamples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.pypackages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.pypackages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.pypyproject.toml
✅ Files skipped from review due to trivial changes (2)
- examples/experimental/cursor_agent_adapter/README.md
- examples/experimental/hermes_agent_adapter/README.md
🚧 Files skipped from review as they are similar to previous changes (4)
- examples/experimental/codex_agent_adapter/package.json
- examples/experimental/hermes_agent_adapter/configs/config-relay.yml
- examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.py
- packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py (2)
225-247:⚠️ Potential issue | 🟠 Major | ⚡ Quick winCheck
working_directorybefore relying on theFileNotFoundErrorhandler.
create_subprocess_exec(..., cwd=...)also raisesFileNotFoundErrorfor a missing workspace, so this branch currently reports a badworking_directoryas a missing Relay binary. Validating the directory up front will avoid a very misleading failure mode.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py` around lines 225 - 247, The FileNotFoundError from asyncio.create_subprocess_exec can come from a missing working directory, so in _run_codex_cli validate cwd (from Path(config.working_directory).resolve()) exists and is a directory before calling create_subprocess_exec; if it does not exist raise a clear RuntimeError about the invalid working_directory (and still cleanup relay_temp_dir) instead of falling through to the subprocess FileNotFoundError handler that assumes the relay binary is missing. Ensure the check uses the same cwd variable and keep relay_temp_dir.cleanup() on error paths.
172-175:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve argv boundaries when writing the Relay command.
This uses
" ".join(...)to serialize the executable plus args intoconfig.toml, which breaks as soon as any configured path or argument contains whitespace. Please quote/escape the argv list before handing it to Relay.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py` around lines 172 - 175, The code in _write_relay_config currently flattens argv with " ".join, losing argument boundaries; instead build the argv list and serialize it (e.g., JSON/TOML array) so spaces are preserved: construct args = [config.command, *config.command_args, *_build_codex_root_args(config)] and write that serialized list into the TOML (use json.dumps(args) or a TOML array representation) when calling path.write_text; update references to config.command, config.command_args and _build_codex_root_args to use the list form rather than a joined string.examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py (1)
141-144:⚠️ Potential issue | 🟠 Major | ⚡ Quick winSerialize the Relay command with proper quoting.
The current
" ".join(...)drops argv boundaries, so whitespace-bearing paths or launcher arguments are persisted incorrectly intoconfig.toml. That is especially risky here because this adapter explicitly encourages launcher wrappers incommand_args.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py` around lines 141 - 144, The current _write_relay_config builds hermes_command with " ".join(...) which flattens argv boundaries and loses quoting for whitespace-bearing paths; instead serialize the command as an array to preserve each argv element. Update _write_relay_config (referencing HermesAgentWorkflowConfig, config.command and config.command_args, and Path.write_text) to write the command field as a JSON array (i.e., json.dumps([config.command, *config.command_args])) into the TOML snippet so each argument is preserved exactly.examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py (1)
167-170:⚠️ Potential issue | 🟠 Major | ⚡ Quick winShell-escape the Relay command string.
commandandcommand_argsare flattened with a plain" ".join(...), so any absolute path or launcher arg containing spaces/quotes is re-tokenized incorrectly inconfig.toml. That breaks a valid configuration shape that this adapter explicitly supports.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py` around lines 167 - 170, The current _write_relay_config flattens ClaudeCodeAgentWorkflowConfig.command and .command_args using " ".join which re-tokenizes paths with spaces/quotes; instead import shlex and build the full argv list ([config.command] + config.command_args) and use shlex.join(...) to produce a properly shell-escaped command string before json.dumps and path.write_text; update the function _write_relay_config to use shlex.join on that argv list (and add the shlex import) so path.write_text writes a safe, quoted command to the TOML.examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py (1)
159-163:⚠️ Potential issue | 🟠 Major | ⚡ Quick winQuote the configured command before persisting it to Relay config.
A plain
" ".join(...)loses the original argv boundaries, so validcommand/command_argsvalues with spaces are serialized incorrectly. This makes the advertised absolute-path/launcher configuration brittle.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py` around lines 159 - 163, The current _write_relay_config function flattens argv with " ".join which loses argument boundaries; instead serialize the command as a JSON array to preserve argv. Replace cursor_command = " ".join([config.command, *config.command_args]) with using the list [config.command, *config.command_args] and write it via json.dumps (e.g., f"command = {json.dumps([config.command, *config.command_args])}\n") while keeping patch_restore_hooks written as before; this ensures CursorAgentWorkflowConfig.command and command_args are preserved exactly in the Relay config.
🧹 Nitpick comments (4)
examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py (1)
260-278: ⚡ Quick winDocument and type the exported workflow entrypoint.
hermes_agentis public but still has no docstring or return annotation. As per coding guidelines "All public APIs require Python 3.11+ type hints on parameters and return values" and "Provide Google-style docstrings for every public module, class, function and CLI command".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py` around lines 260 - 278, The public async function hermes_agent lacks a Google-style docstring and an explicit return type annotation; add a concise docstring above hermes_agent describing its purpose, parameters (config: HermesAgentWorkflowConfig, _builder: Builder), and the yielded value, and annotate its signature with the correct return type (e.g., -> AsyncGenerator[FunctionInfo, None]) to reflect that it yields a FunctionInfo; ensure the docstring also briefly documents what _response_fn and _stream_fn do and what FunctionInfo.create yields so callers and type checkers can understand the API.examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py (1)
269-287: ⚡ Quick winAdd the public entrypoint docstring and return annotation.
claude_code_agentis an exported workflow, but it currently has neither a docstring nor an explicit return type. As per coding guidelines "All public APIs require Python 3.11+ type hints on parameters and return values" and "Provide Google-style docstrings for every public module, class, function and CLI command".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py` around lines 269 - 287, The public async workflow function claude_code_agent lacks a Google-style docstring and an explicit return type; add a module-level docstring if missing and add a Google-style docstring immediately under the async def claude_code_agent(...) describing purpose, parameters (config: ClaudeCodeAgentWorkflowConfig, _builder: Builder) and returns. Also add an explicit return annotation to claude_code_agent such as -> AsyncGenerator[FunctionInfo, None] (or the project's preferred AsyncGenerator generic) to reflect that the function yields FunctionInfo; keep existing inner helpers (_response_fn, _stream_fn) unchanged.examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py (1)
281-299: ⚡ Quick winDocument and annotate the exported workflow function.
codex_agentis a public entrypoint, but it still lacks both a docstring and an explicit return type. As per coding guidelines "All public APIs require Python 3.11+ type hints on parameters and return values" and "Provide Google-style docstrings for every public module, class, function and CLI command".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py` around lines 281 - 299, Add a Google-style docstring and an explicit return type to the public async generator function codex_agent: annotate its signature with an appropriate AsyncGenerator return type (e.g., -> AsyncGenerator[FunctionInfo, None] or the project's exact FunctionInfo wrapper type) and include a docstring that briefly describes the workflow's purpose, its parameters (config: CodexAgentWorkflowConfig, _builder: Builder), and what it yields (FunctionInfo containing single_fn and stream_fn). Keep the docstring concise and place it immediately under the def codex_agent(...) line; you do not need to change the inner helper functions (_response_fn/_stream_fn) unless they are part of the public API.examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py (1)
277-295: ⚡ Quick winAdd the missing public API docs and return type.
cursor_agentis exported, but it has no docstring and no explicit return annotation. As per coding guidelines "All public APIs require Python 3.11+ type hints on parameters and return values" and "Provide Google-style docstrings for every public module, class, function and CLI command".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py` around lines 277 - 295, Add a Google-style docstring to the exported async generator function cursor_agent describing its purpose, parameters (config: CursorAgentWorkflowConfig, _builder: Builder), and what it yields (FunctionInfo instances) using Args and Yields sections; also add an explicit return type annotation indicating it is an async generator that yields FunctionInfo (e.g., -> AsyncGenerator[FunctionInfo, None]) and import AsyncGenerator from typing if not present so the signature and docs satisfy the public-API guidelines.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`:
- Around line 213-235: In _run_claude_code_cli validate that
Path(config.working_directory).resolve() exists and is a directory before
creating the subprocess: check cwd.exists() and cwd.is_dir(), call
relay_temp_dir.cleanup() and raise a clear RuntimeError indicating the provided
working_directory is invalid (include the path) so a bad workspace is reported
instead of a FileNotFoundError about the relay/claude command; keep the existing
FileNotFoundError handler for missing executables.
In
`@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py`:
- Around line 222-244: The FileNotFoundError except block in _run_cursor_agent
currently conflates a missing working directory with a missing executable;
before attempting asyncio.create_subprocess_exec, validate cwd =
Path(config.working_directory).resolve() (or use Path(config.working_directory)
then resolve only after existence) and raise a clear RuntimeError (and cleanup
relay_temp_dir) if the directory does not exist or is not a directory, so that
the existing except FileNotFoundError only handles missing executable errors
from asyncio.create_subprocess_exec; update the pre-subprocess logic in
_run_cursor_agent to check cwd.exists() and cwd.is_dir() and handle
cleanup/raise accordingly.
In
`@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py`:
- Around line 205-227: The FileNotFoundError raised by
asyncio.create_subprocess_exec can be caused by a missing working directory as
well as a missing executable; before calling asyncio.create_subprocess_exec in
_run_hermes_agent, validate that Path(config.working_directory).resolve() (cwd)
exists and is a directory and if not, call relay_temp_dir.cleanup() and raise a
clear RuntimeError that the configured working_directory is invalid (include the
invalid path), keeping the existing FileNotFoundError except-block to handle the
missing executable/uvx case separately.
---
Outside diff comments:
In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`:
- Around line 167-170: The current _write_relay_config flattens
ClaudeCodeAgentWorkflowConfig.command and .command_args using " ".join which
re-tokenizes paths with spaces/quotes; instead import shlex and build the full
argv list ([config.command] + config.command_args) and use shlex.join(...) to
produce a properly shell-escaped command string before json.dumps and
path.write_text; update the function _write_relay_config to use shlex.join on
that argv list (and add the shlex import) so path.write_text writes a safe,
quoted command to the TOML.
In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`:
- Around line 225-247: The FileNotFoundError from asyncio.create_subprocess_exec
can come from a missing working directory, so in _run_codex_cli validate cwd
(from Path(config.working_directory).resolve()) exists and is a directory before
calling create_subprocess_exec; if it does not exist raise a clear RuntimeError
about the invalid working_directory (and still cleanup relay_temp_dir) instead
of falling through to the subprocess FileNotFoundError handler that assumes the
relay binary is missing. Ensure the check uses the same cwd variable and keep
relay_temp_dir.cleanup() on error paths.
- Around line 172-175: The code in _write_relay_config currently flattens argv
with " ".join, losing argument boundaries; instead build the argv list and
serialize it (e.g., JSON/TOML array) so spaces are preserved: construct args =
[config.command, *config.command_args, *_build_codex_root_args(config)] and
write that serialized list into the TOML (use json.dumps(args) or a TOML array
representation) when calling path.write_text; update references to
config.command, config.command_args and _build_codex_root_args to use the list
form rather than a joined string.
In
`@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py`:
- Around line 159-163: The current _write_relay_config function flattens argv
with " ".join which loses argument boundaries; instead serialize the command as
a JSON array to preserve argv. Replace cursor_command = "
".join([config.command, *config.command_args]) with using the list
[config.command, *config.command_args] and write it via json.dumps (e.g.,
f"command = {json.dumps([config.command, *config.command_args])}\n") while
keeping patch_restore_hooks written as before; this ensures
CursorAgentWorkflowConfig.command and command_args are preserved exactly in the
Relay config.
In
`@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py`:
- Around line 141-144: The current _write_relay_config builds hermes_command
with " ".join(...) which flattens argv boundaries and loses quoting for
whitespace-bearing paths; instead serialize the command as an array to preserve
each argv element. Update _write_relay_config (referencing
HermesAgentWorkflowConfig, config.command and config.command_args, and
Path.write_text) to write the command field as a JSON array (i.e.,
json.dumps([config.command, *config.command_args])) into the TOML snippet so
each argument is preserved exactly.
---
Nitpick comments:
In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`:
- Around line 269-287: The public async workflow function claude_code_agent
lacks a Google-style docstring and an explicit return type; add a module-level
docstring if missing and add a Google-style docstring immediately under the
async def claude_code_agent(...) describing purpose, parameters (config:
ClaudeCodeAgentWorkflowConfig, _builder: Builder) and returns. Also add an
explicit return annotation to claude_code_agent such as ->
AsyncGenerator[FunctionInfo, None] (or the project's preferred AsyncGenerator
generic) to reflect that the function yields FunctionInfo; keep existing inner
helpers (_response_fn, _stream_fn) unchanged.
In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`:
- Around line 281-299: Add a Google-style docstring and an explicit return type
to the public async generator function codex_agent: annotate its signature with
an appropriate AsyncGenerator return type (e.g., -> AsyncGenerator[FunctionInfo,
None] or the project's exact FunctionInfo wrapper type) and include a docstring
that briefly describes the workflow's purpose, its parameters (config:
CodexAgentWorkflowConfig, _builder: Builder), and what it yields (FunctionInfo
containing single_fn and stream_fn). Keep the docstring concise and place it
immediately under the def codex_agent(...) line; you do not need to change the
inner helper functions (_response_fn/_stream_fn) unless they are part of the
public API.
In
`@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py`:
- Around line 277-295: Add a Google-style docstring to the exported async
generator function cursor_agent describing its purpose, parameters (config:
CursorAgentWorkflowConfig, _builder: Builder), and what it yields (FunctionInfo
instances) using Args and Yields sections; also add an explicit return type
annotation indicating it is an async generator that yields FunctionInfo (e.g.,
-> AsyncGenerator[FunctionInfo, None]) and import AsyncGenerator from typing if
not present so the signature and docs satisfy the public-API guidelines.
In
`@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py`:
- Around line 260-278: The public async function hermes_agent lacks a
Google-style docstring and an explicit return type annotation; add a concise
docstring above hermes_agent describing its purpose, parameters (config:
HermesAgentWorkflowConfig, _builder: Builder), and the yielded value, and
annotate its signature with the correct return type (e.g., ->
AsyncGenerator[FunctionInfo, None]) to reflect that it yields a FunctionInfo;
ensure the docstring also briefly documents what _response_fn and _stream_fn do
and what FunctionInfo.create yields so callers and type checkers can understand
the API.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 6c35bb85-09be-4c49-a459-858cf0335c87
📒 Files selected for processing (23)
examples/experimental/claude_code_agent_adapter/README.mdexamples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/claude_code_agent_adapter/configs/config-relay.ymlexamples/experimental/claude_code_agent_adapter/pyproject.tomlexamples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.pyexamples/experimental/codex_agent_adapter/README.mdexamples/experimental/codex_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/codex_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/codex_agent_adapter/configs/config-relay.ymlexamples/experimental/codex_agent_adapter/pyproject.tomlexamples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.pyexamples/experimental/cursor_agent_adapter/README.mdexamples/experimental/cursor_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/cursor_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/cursor_agent_adapter/configs/config-relay.ymlexamples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.pyexamples/experimental/hermes_agent_adapter/README.mdexamples/experimental/hermes_agent_adapter/configs/config-relay-phoenix-eval.ymlexamples/experimental/hermes_agent_adapter/configs/config-relay-phoenix.ymlexamples/experimental/hermes_agent_adapter/configs/config-relay.ymlexamples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.pyexamples/experimental/openclaw_agent_adapter/README.md
💤 Files with no reviewable changes (10)
- examples/experimental/hermes_agent_adapter/configs/config-relay.yml
- examples/experimental/hermes_agent_adapter/configs/config-relay-phoenix-eval.yml
- examples/experimental/claude_code_agent_adapter/configs/config-relay.yml
- examples/experimental/hermes_agent_adapter/configs/config-relay-phoenix.yml
- examples/experimental/claude_code_agent_adapter/pyproject.toml
- examples/experimental/cursor_agent_adapter/configs/config-relay.yml
- examples/experimental/cursor_agent_adapter/configs/config-relay-phoenix-eval.yml
- examples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix-eval.yml
- examples/experimental/cursor_agent_adapter/configs/config-relay-phoenix.yml
- examples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix.yml
✅ Files skipped from review due to trivial changes (6)
- examples/experimental/cursor_agent_adapter/README.md
- examples/experimental/codex_agent_adapter/configs/config-relay.yml
- examples/experimental/hermes_agent_adapter/README.md
- examples/experimental/openclaw_agent_adapter/README.md
- examples/experimental/codex_agent_adapter/README.md
- examples/experimental/claude_code_agent_adapter/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
- examples/experimental/codex_agent_adapter/configs/config-relay-phoenix-eval.yml
- examples/experimental/codex_agent_adapter/configs/config-relay-phoenix.yml
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
mnajafian-nv
left a comment
There was a problem hiding this comment.
LGTM with one inline nit :) great work!
Salonijain27
left a comment
There was a problem hiding this comment.
Approved from a dependency point of view
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
04ed0a4 to
a2a2569
Compare
|
/merge |
…ia-ai-endpoints bump The uv.lock files for the experimental coding-agent adapters (added in #1995) still pinned langchain-nvidia-ai-endpoints>=1.3.0,<2.0.0. #1995 merged after #2002 bumped that dependency to >=1.4.1,<2.0.0 in nvidia_nat_langchain, but its branch was locked against the pre-bump state, so the lockfiles were never regenerated. This left the uv-lock-all-pyprojects pre-commit hook failing on any full run. Re-locked with uv 0.9.28 to match CI. Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Description
Adds experimental NVIDIA NeMo Agent Toolkit workflow adapters for five coding-agent harnesses:
Each adapter is packaged as an installable example with a
nat.componentsentry point, a primitive workflow_type, Relay-enabled configs, Phoenix tracing configs, smoke eval configs, and README guidance.This also adds an experimental Relay telemetry bridge used by the Relay-backed adapters, plus Phoenix trace screenshots for the verified workflows.
By Submitting this PR I confirm:
Summary by CodeRabbit
New Features
Documentation
Tests
Chores